//
// Created by korack on 25-5-21.
//

#include "Buttons.h"

struct _Buttons
{
        void *object;
        //
        ButtonIRQHandler irq_handler;
};

static bool    is_inited = false;
static Buttons global_buttons;

Buttons *
buttons_new_from_global(void)
{
        if (is_inited)
                return &global_buttons;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,
                               ENABLE);
        GPIO_InitTypeDef gpio = {.GPIO_Mode = GPIO_Mode_IPU,
                                 .GPIO_Pin =
                                         GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9,
                                 .GPIO_Speed = GPIO_Speed_50MHz};
        GPIO_Init(GPIOB, &gpio);
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
        EXTI_InitTypeDef exti = {.EXTI_Line =
                                         EXTI_Line7 | EXTI_Line8 | EXTI_Line9,
                                 .EXTI_LineCmd = ENABLE,
                                 .EXTI_Mode    = EXTI_Mode_Interrupt,
                                 .EXTI_Trigger = EXTI_Trigger_Falling};
        EXTI_Init(&exti);
        NVIC_InitTypeDef nvic = {.NVIC_IRQChannel    = EXTI9_5_IRQn,
                                 .NVIC_IRQChannelCmd = ENABLE,
                                 .NVIC_IRQChannelPreemptionPriority = 1,
                                 .NVIC_IRQChannelSubPriority        = 1};
        NVIC_Init(&nvic);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,
                               ENABLE);
        gpio.GPIO_Pin = GPIO_Pin_12;
        GPIO_Init(GPIOA, &gpio);
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource12);
        exti.EXTI_Line = EXTI_Line12;
        EXTI_Init(&exti);
        nvic.NVIC_IRQChannel = EXTI15_10_IRQn;
        NVIC_Init(&nvic);

        global_buttons.object      = NULL;
        global_buttons.irq_handler = NULL;
        //
        is_inited = true;
        return &global_buttons;
}

void
buttons_connect_handler(Buttons               *self,
                        void                  *object,
                        const ButtonIRQHandler handler)
{
        self->irq_handler = handler;
        self->object      = object;
}

void
EXTI9_5_IRQHandler(void)
{
        if (EXTI_GetITStatus(EXTI_Line8) == SET) {
                if (global_buttons.irq_handler && global_buttons.object)
                        global_buttons.irq_handler(global_buttons.object, 's');
                EXTI_ClearITPendingBit(EXTI_Line8);
        }
        if (EXTI_GetITStatus(EXTI_Line7) == SET) {
                if (global_buttons.irq_handler && global_buttons.object)
                        global_buttons.irq_handler(global_buttons.object, 'a');
                EXTI_ClearITPendingBit(EXTI_Line7);
        }
        if (EXTI_GetITStatus(EXTI_Line9) == SET) {
                if (global_buttons.irq_handler && global_buttons.object)
                        global_buttons.irq_handler(global_buttons.object, 'f');
                EXTI_ClearITPendingBit(EXTI_Line9);
        }
}

void
EXTI15_10_IRQHandler(void)
{
        if (EXTI_GetITStatus(EXTI_Line12) == SET) {
                if (global_buttons.irq_handler && global_buttons.object)
                        global_buttons.irq_handler(global_buttons.object, 'h');
                EXTI_ClearITPendingBit(EXTI_Line12);
        }
}
